package ginplusplus

import (
	"fmt"
	"net/http"
	"reflect"
	"strconv"

	"gitee.com/freelifer/pkg/errors"
	"gitee.com/freelifer/pkg/json"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
)

// StatusText 定义状态文本
type StatusText string

func (t StatusText) String() string {
	return string(t)
}

// 定义HTTP状态文本常量
const (
	OKStatus    StatusText = "OK"
	ErrorStatus StatusText = "ERROR"
	FailStatus  StatusText = "FAIL"
)

// StatusResult 响应状态
type StatusResult struct {
	Status StatusText `json:"status"` // 状态(OK)
}

// ErrorResult 响应错误
type ErrorResult struct {
	Error ErrorItem `json:"error"` // 错误项
}

// ErrorItem 响应错误项
type ErrorItem struct {
	Code    int    `json:"code"`    // 错误码
	Message string `json:"message"` // 错误信息
}

// ResOK 响应OK
func ResOK(c *gin.Context) {
	ResSuccess(c, StatusResult{Status: OKStatus})
}

// ResList 响应列表数据
// func ResList(c *gin.Context, v interface{}) {
// 	ResSuccess(c, schema.ListResult{List: v})
// }

// ResPage 响应分页数据
// func ResPage(c *gin.Context, v interface{}, pr *schema.PaginationResult) {
// 	list := schema.ListResult{
// 		List:       v,
// 		Pagination: pr,
// 	}
// 	ResSuccess(c, list)
// }

// ResSuccess 响应成功
func ResSuccess(c *gin.Context, v interface{}) {
	ResJSON(c, http.StatusOK, v)
}

// ResJSON 响应JSON数据
func ResJSON(c *gin.Context, status int, v interface{}) {
	buf, err := json.Marshal(v)
	if err != nil {
		panic(err)
	}
	// c.Set(ResBodyKey, buf)
	c.Data(status, "application/json; charset=utf-8", buf)
	c.Abort()
}

// ResError 响应错误
func ResError(c *gin.Context, err error, status ...int) {
	var res *errors.ResponseError
	if err != nil {
		if e, ok := err.(*errors.ResponseError); ok {
			res = e
		} else {
			res = errors.UnWrapResponse(errors.Wrap500Response(err))
		}
	} else {
		res = errors.UnWrapResponse(errors.ErrInternalServer)
	}

	if len(status) > 0 {
		res.StatusCode = status[0]
	}

	if err := res.ERR; err != nil {
		if status := res.StatusCode; status >= 400 && status < 500 {
			fmt.Println(err.Error())
		} else if status >= 500 {
			fmt.Println("stack", fmt.Sprintf("%+v", err))
		}
	}

	eitem := ErrorItem{
		Code:    res.Code,
		Message: res.Message,
	}
	ResJSON(c, res.StatusCode, ErrorResult{Error: eitem})
}

// 解析请求参数

// ParseParam 解析Query参数
func ParseParam(c *gin.Context, key string, obj interface{}) error {
	if err := cover(c.Param(key), obj); err != nil {
		return errors.Wrap400Response(err, fmt.Sprintf("解析请求参数发生错误 - %s", err.Error()))
	}
	return nil
}

// ParseQuery 解析Query参数
func ParseQuery(c *gin.Context, obj interface{}) error {
	if err := c.ShouldBindQuery(obj); err != nil {
		return errors.Wrap400Response(err, fmt.Sprintf("解析请求参数发生错误 - %s", err.Error()))
	}
	return nil
}

// ParseJSON 利用JSON解析请求Body体
func ParseJSON(c *gin.Context, obj interface{}) error {
	if err := c.ShouldBindJSON(obj); err != nil {
		return errors.Wrap400Response(err, fmt.Sprintf("解析请求参数发生错误 - %s", err.Error()))
	}
	return nil
}

// ParseForm 解析Form请求
func ParseForm(c *gin.Context, obj interface{}) error {
	if err := c.ShouldBindWith(obj, binding.Form); err != nil {
		return errors.Wrap400Response(err, fmt.Sprintf("解析请求参数发生错误 - %s", err.Error()))
	}
	return nil
}

// 转换 string -> 各个类型的int
func cover(value string, obj interface{}) error {
	rType := reflect.TypeOf(obj)
	rVal := reflect.ValueOf(obj)
	if rType.Kind() == reflect.Ptr {
		// 传入的inStructPtr是指针，需要.Elem()取得指针指向的value
		rType = rType.Elem()
		rVal = rVal.Elem()
		switch rType.Kind() {
		case reflect.Int32:
			result, err := strconv.Atoi(value)
			if err != nil {
				return err
			}
			rVal.Set(reflect.ValueOf(int32(result)))
		case reflect.Int:
			result, err := strconv.Atoi(value)
			if err != nil {
				return err
			}
			rVal.Set(reflect.ValueOf(result))
		case reflect.Int64:
			result, err := strconv.ParseInt(value, 10, 64)
			if err != nil {
				return err
			}
			rVal.Set(reflect.ValueOf(result))
		default:
		}

	} else {
		// panic("inStructPtr must be ptr to struct")
	}

	return nil
}
